#ifndef _GAME_H_
#define _GAME_H_

#include <vector>
#include <map>

#include "../tools/thread_safe_containers/Queue.h"
#include "../tools/thread_safe_containers/Vector.h"
#include "commands/GameCommand.h"
#include "Game.h"
#include "GameConf.h"

using namespace std;

/*	MAX_FPS: 	The maximum number of game frames that will be simulated each second
	MIN_FPS:	The minimum number of game frames that will be simulated each second. If this number can't be maintained
 			 	by a particular peer for some amount of time, the offending peer will be dropped.
 	NUM_SLOW_FRAMES_BEFORE_INCREASE:	# of frames that were simulated too slowly before game frame length is increased
	FRAME_LENGTH_PERCENT_INCREASE:		When frame length is increased, the amount by which it is increased
*/
#define MAX_FPS	8
//#define MIN_FPS 2
#define NUM_SLOW_FRAMES_BEFORE_INCREASE 3
#define FRAME_LENGTH_PERCENT_INCREASE 25

class GameNetwork;

class GameControl
{
	static GameControl* thisInstance;
	
	Game g;								// Game instance that GameControl owns
	GameNetwork *network;				// If this is a network game, this is Game's network interface. NULL othewrise.
	
	pthread_t game_thread;
	
	unsigned long game_time;			// The sum of each game frame's agreed upon time thus far
	unsigned long game_frame_length;	// Current length of game frames (peers agree on this dynamically)
	unsigned long last_increase;		// The last game_time that game_frame_length was increased
	unsigned long command_latency;		// The time between when a local command is issued and when it is executed
	
	bool gamePaused;				// Whether the game is paused
	
public:
	static inline GameControl* Instance() { return GameControl::thisInstance; }
	
	static void* game_thread_main(void* data);
	
	bool run;
	
	void main_loop();
	void let_network_get_ahead();
	
	GameControl();
	GameControl(const GameControl&);
	~GameControl();
	
	GameControl& operator=(const GameControl&) { return *this; }
	
	/*	Thread-safe containers for game commands. In a non-network game, the commands passed to command_queue will be
		evaluated the next frame. In a network game, command evaluation is delayed COMMAND_LATENCY ms.
	*/
	Priority_Queue <GameCommand *, vector<GameCommand *>, GameCommandPointerLessThan> command_queue;
	Vector <GameCommand *> command_buffer;		// Commands Game is buffering to pass to Network for Network's next frame
	
	void init(const string game_config_file, const GameConf& game_conf);
	void step(unsigned dt);
	void kill();
	
	void pauseGame();
	void resumeGame();
	bool isPaused()	{	return gamePaused;	}
	
	void appendGameCommand(GameCommand*);
	
	unsigned long get_game_time();
	unsigned long get_command_horizon();	// = game_time + command_latency (the point at which we're issuing future commands)
	
	void increase_frame_length();		// Game_LengthenFrame
	
	void onWindowResize(float W, float H);
};

#endif
